﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Configuration;


namespace NabNetLib
{
    public class XmppListener
    {
        private bool mShuttingDown = false;
        

        private TcpListener mListenerXmpp;
        private List<Thread> mThreadList = new List<Thread>();
        private static List<XmppServerConnection> mXmppConnections = new List<XmppServerConnection>(); 


        private static readonly object mLocker = new object();

        public void Main()
        {
            try
            {
                Logger.Log(LogType.Info, "Start XMPP Listener");

                mListenerXmpp = new TcpListener(IPAddress.Any, 5222);
                mListenerXmpp.Start();

                while (!mShuttingDown)
                {
                    Socket soc = mListenerXmpp.AcceptSocket();

                    long limit = 5;
                    long.TryParse(ConfigurationManager.AppSettings["LIMIT"], out limit);

                    if (mThreadList.Count < limit)
                    {
                        Logger.Log(LogType.Info, "Accepting new connection : "+soc.RemoteEndPoint);
                        ParameterizedThreadStart pts = new ParameterizedThreadStart(XmppServiceThread);

                        Thread t = new Thread(pts);

                        RegisterThread(t);

                        t.Start(soc);
                    }
                    else
                    {
                        Logger.Log(LogType.Info, "Maximum connection, shutting down socket ("+soc.RemoteEndPoint+")");
                        soc.Disconnect(false);
                    }
                }
                Logger.Log(LogType.Info, "XMPP Listener End");
            } catch (Exception ex)
            {
                Logger.Log("XMPP Listener Error",ex);
                throw;
            }
        }

        private void RegisterThread(Thread t)
        {
            lock (mLocker)
            {
                mThreadList.Add(t);
            }
        }

        private void UnregisterThread(Thread t)
        {
            lock (mLocker)
            {
                if (mThreadList.Contains(t))
                {
                    mThreadList.Remove(t);
                }
            }
        }

        public void ShutDown()
        {
            try
            {
                Logger.Log(LogType.Info, "Shutting down XMPP Listener");
                mShuttingDown = true;
                mListenerXmpp.Stop();

                foreach (Thread thread in mThreadList)
                {
                    if (thread.IsAlive)
                    {
                        thread.Abort();
                    }

                }
            }
            catch (Exception ex)
            {
                Logger.Log("Error during ShutDown", ex);
                throw;
            }
        }

        private void XmppServiceThread(object s)
        {
            try {
            Socket socket = (Socket) s;

            using (nabnetEntities objectContext = new nabnetEntities())
            {
                objectContext.ContextOptions.LazyLoadingEnabled = true;
                XmppServerConnection xsc = new XmppServerConnection(socket, objectContext);
                lock (mLocker)
                {
                    mXmppConnections.Add(xsc);
                }
                
                xsc.Start();

                lock (mLocker)
                {
                    mXmppConnections.Remove(xsc);
                }
            }

            UnregisterThread(Thread.CurrentThread);
            }
            catch (Exception ex)
            {
                Logger.Log("Error during connection",ex);
                throw;
            }
        }

        public static void SendRfidMessage(string lapinSerialNumber, string rfidSerialNumber)
        {
            try
            {
                XmppServerConnection connection = null;
                lock (mLocker)
                {
                    connection =
                        (from c in mXmppConnections
                         where c.Lapin != null && c.Lapin.serial_number == lapinSerialNumber
                         select c).FirstOrDefault();

                    if (connection != null)
                    {
                        connection.RfidMessage(rfidSerialNumber);
                    }
                }
            } catch(Exception ex)
            {
                Logger.Log("Error during SendRfidMessage", ex);
                throw;
            }
        }

        public static void SendRecordMessage(string lapinSerialNumber, string wavPath)
        {
            try
            {
                XmppServerConnection connection = null;
                lock (mLocker)
                {
                    connection =
                        (from c in mXmppConnections
                         where c.Lapin != null && c.Lapin.serial_number == lapinSerialNumber
                         select c).FirstOrDefault();

                    if (connection != null)
                    {
                        connection.RecordMessage(wavPath);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Log("Error during SendRecordMessage", ex);
                throw;
            }
        }

        internal static IEnumerable<XmppServerConnection> GetXmppConnections(Plugin p)
        {
            try
            {
                lock (mLocker)
                {
                    return (from c in mXmppConnections
                            where c.Lapin != null && c.Lapin.State == LapinState.Ready && c.Lapin.Plugins.Contains(p)
                            select c);
                }
            } catch (Exception ex)
            {
                Logger.Log("Error during GetXmppConnections", ex);
                throw;
            }
        }
    }
}
